package com.jack.rpc.server;

import org.omg.CORBA.ServerRequest;

import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.lang.reflect.Method;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.Collections;
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.ArrayBlockingQueue;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;

/**
 * @author jie
 * @date 2018/8/9
 */
public class RpcServer {

    /**
     * 服务暴露端口
     **/
    private int serverPort;

    /**
     * 接口注册容器
     */
    private Map<String, Class<?>> serviceRegisty = Collections.synchronizedMap(new HashMap<String, Class<?>>());

    private static ThreadPoolExecutor threadPoolExecutor = new ThreadPoolExecutor(3, 5, 200, TimeUnit.MILLISECONDS,
            new ArrayBlockingQueue<Runnable>(10));

    public RpcServer(int serverPort) {
        this.serverPort = serverPort;
    }

    /**
     * 注册服务接口
     * @param interfaceClass
     * @param implClass
     */
    public void registyService(Class<?> interfaceClass, Class<?> implClass) {
        serviceRegisty.put(interfaceClass.getName(), implClass);
    }

    /**
     * 启动服务端
     */
    public void start(){
        try (ServerSocket serverSocket = new ServerSocket(serverPort)) {
            while (true) {
                threadPoolExecutor.execute(new RpcTask(serverSocket.accept()));
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    private class RpcTask implements Runnable {

        private Socket client;

        public RpcTask(Socket client) {
            this.client = client;
        }

        @Override
        public void run() {
            try (ObjectOutputStream serializer = new ObjectOutputStream(client.getOutputStream());
                 ObjectInputStream deSerializer = new ObjectInputStream(client.getInputStream())) {
                String interfaceClass = deSerializer.readUTF();
                String methodName = deSerializer.readUTF();
                Class<?>[] methodParamTypes = (Class<?>[]) deSerializer.readObject();
                Object[] methodParams = (Object[]) deSerializer.readObject();

                Class<?> serviceImpClass = serviceRegisty.get(interfaceClass);
                Method method = serviceImpClass.getMethod(methodName, methodParamTypes);
                if(serviceImpClass != null){
                    Object result = method.invoke(serviceImpClass.newInstance(), methodParams);
                    serializer.writeObject(result);
                    serializer.flush();
                }
            } catch (Exception e) {
                e.printStackTrace();
            } finally {
                if(client != null){
                    try {
                        client.close();
                    } catch (IOException e) {
                        e.printStackTrace();
                    }
                }
            }
        }
    }
}
